package com.example.drive_safe;

import java.io.IOException;
import java.util.ArrayList;
import java.util.List;

import android.content.Context;
import android.location.Criteria;
import android.location.Location;
import android.location.LocationListener;
import android.location.LocationManager;
import android.os.Bundle;

public class GPSManager {

	private static final int gpsMinTime = 500;
	private static final int gpsMinDistance = 0;

	private static LocationManager locationManager = null;
	private static LocationListener locationListener = null;
	private static GPSCallback gpsCallback = null;

	private final String MOCK_LOCAION_PROVIDER = "FAKE_PROVIDER";

	// GPSManager constructor
	public GPSManager() {
		GPSManager.locationListener = new LocationListener() {

			@Override
			public void onStatusChanged(String provider, int status,
					Bundle extras) {

			}

			@Override
			public void onProviderEnabled(String provider) {
				// TODO Auto-generated method stub

			}

			@Override
			public void onProviderDisabled(String provider) {
				// TODO Auto-generated method stub

			}

			@Override
			//update the location of the  vehicle  
			public void onLocationChanged(Location location) {
				if (GPSManager.gpsCallback != null) {
					GPSManager.gpsCallback.onGPSUpdate(location);
				}
			}
		};

	}
    
	// Get GPScallback
	public GPSCallback getGPSCallback() {
		return GPSManager.gpsCallback;
	}
    
	 // Set data from gpscallback
	public void setGPSCallback(GPSCallback gpsCallback) {
		GPSManager.gpsCallback = gpsCallback;
	}

	// When the GPS starts...
	// start listening the location of the vehicle from the location_service based on the specified criteria 
	public void startListner(final Context context) {
		if (GPSManager.locationManager == null) {
			GPSManager.locationManager = (LocationManager) context
					.getSystemService(Context.LOCATION_SERVICE);
		}
         
		final Criteria criteria = new Criteria();
        
		//periodic updates of the user's current location from a location provider by specifying  criteria 
		
		// set the constant to describe horizontal accuracy of this provider
		criteria.setAccuracy(Criteria.ACCURACY_FINE);
		criteria.setSpeedRequired(true);
		criteria.setAltitudeRequired(false);
		criteria.setBearingRequired(false);
		criteria.setCostAllowed(true);
		criteria.setPowerRequirement(Criteria.POWER_LOW);
        
		// Read the location data provided by the BestProvider depending on the specified criteria 
		final String bestProvider = GPSManager.locationManager.getBestProvider(
				criteria, true);

		if (bestProvider != null && bestProvider.length() > 0) {
			GPSManager.locationManager.requestLocationUpdates(bestProvider,
					GPSManager.gpsMinTime, GPSManager.gpsMinDistance,
					GPSManager.locationListener);
		} else {
			final List<String> providers = GPSManager.locationManager
					.getProviders(true);

			for (final String provider : providers) {
				GPSManager.locationManager.requestLocationUpdates(provider,
						GPSManager.gpsMinTime, GPSManager.gpsMinDistance,
						GPSManager.locationListener);
			}
		}
	}
    
	
	// When GPS stops...
	public void stopListner() {
		try {
			if (GPSManager.locationManager != null
					&& GPSManager.locationListener != null) {
				GPSManager.locationManager
						.removeUpdates(GPSManager.locationListener);
			}

			// Set location manager to null
			GPSManager.locationManager = null;
		} catch (final Exception ex) {
			ex.fillInStackTrace();
		}
	}

	
	// Test code for getSpeed() 
	// using mockLocation provider
	public void startTesting(Context context) {
		GPSManager.locationManager = (LocationManager) context
				.getSystemService(Context.LOCATION_SERVICE);
		String mocLocationProvider = MOCK_LOCAION_PROVIDER;

		if (GPSManager.locationManager.getProvider(mocLocationProvider) != null) {
			GPSManager.locationManager.removeTestProvider(mocLocationProvider);
		}
		GPSManager.locationManager.addTestProvider(mocLocationProvider, false,
				false, false, false, true, true, true, 0, 5);

		GPSManager.locationManager.setTestProviderEnabled(mocLocationProvider,
				true);
		GPSManager.locationManager.requestLocationUpdates(mocLocationProvider,
				0, 0, GPSManager.locationListener);

		try {

			List<String> data = new ArrayList<String>();

			data.add("24.856449265609735,67.04308920288086,54");
			new MockLocationProvider(GPSManager.locationManager,
					mocLocationProvider, data).start();

		} catch (IOException e) {

			e.printStackTrace();
		}
	}

	class MockLocationProvider extends Thread {

		private List<String> data;
		private LocationManager locationManager;
		private String mocLocationProvider;

		public MockLocationProvider(LocationManager locationManager,
				String mocLocationProvider, List<String> data)
				throws IOException {

			this.locationManager = locationManager;
			this.mocLocationProvider = mocLocationProvider;
			this.data = data;
		}

		@Override
		// Read the GPS data in every  5 seconds
		public void run() {
			while(true) {

				for (String str : data) {
	
					try {
	
						Thread.sleep(5000);
	
					} catch (InterruptedException e) {
	
						e.printStackTrace();
					}
	
					// Set one position
					String[] parts = str.split(",");
					Double latitude = Double.valueOf(parts[0]);
					Double longitude = Double.valueOf(parts[1]);
					float speed = Float.valueOf(parts[2]);
					Location location = new Location(mocLocationProvider);
					location.setLatitude(latitude);
					location.setLongitude(longitude);
					location.setSpeed(speed);
	
					// Set the time in the location. 
					// If the time on this location matches the time on the one in the previous set call, 
					// it will be ignored
					location.setTime(System.currentTimeMillis());
	
					locationManager.setTestProviderLocation(mocLocationProvider,
							location);
				}
			}
		}
	}
	
}
